/**
 * 版权所有(C)，上海海鼎信息工程股份有限公司，2007，所有权利保留。
 * 
 * 项目名：	rumba
 * 文件名：	CartridgeMgr.java
 * 模块说明：	
 * 修改历史：
 * Apr 26, 2007 - lxm - 创建。
 */
package com.hd123.rumba.cartridge;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;

import net.sf.hibernate.Hibernate;
import net.sf.hibernate.HibernateException;

import org.apache.log4j.Logger;

import com.hd123.rumba.cartridge.biz.BCartridgeMgr;
import com.hd123.rumba.domain.IDomainMgr;
import com.hd123.rumba.exception.BusinessException;
import com.hd123.rumba.log.EntityLogger;
import com.hd123.rumba.runtime.HibernateSession;
import com.hd123.rumba.runtime.Manager;
import com.hd123.rumba.runtime.NamingMgr;
import com.hd123.rumba.runtime.OperateContext;
import com.hd123.rumba.util.Version;

/**
 * 构件包 | 管理员 | 实现类
 * 
 * @author lxm
 * 
 */
public class CartridgeMgr extends Manager implements ICartridgeMgr {

  public static final String CAPTION_MANAGER = "构件包管理员";

  /* Events */
  private static final String EVENT_ADDNEW_CFV = "添加功能视图";
  private static final String EVENT_MODIFY_CFV = "修改功能视图";
  private static final String EVENT_REMOVE_CFV = "删除功能视图";

  public CartridgeMgr() {
    super();
    this.registryClass(ICartridge.class.getName(), Cartridge.class.getName());
    this.registryClass(ICartFunctionView.class.getName(), CartFunctionView.class.getName());
  }

  public ICartridge createCartridge() throws BusinessException, HibernateException {
    ICartridge cart = new Cartridge();
    IDomainMgr dmMgr = (IDomainMgr) NamingMgr.getInstance().lookupMgr(IDomainMgr.class);
    cart.setDomain(dmMgr.getRootDomain());
    return cart;
  }

  public ICartFunctionView createFunctionView(ICartridge cartridge) throws BusinessException {
    this.checkParameterNotNull(cartridge, "cartridge");
    ICartFunctionView cfv = new CartFunctionView();
    cfv.setCartridge(cartridge);
    cfv.setDomain(cartridge.getDomain());
    return cfv;
  }

  public void saveCartridge(ICartridge cartridge, OperateContext operate) throws BusinessException,
      HibernateException {
    this.checkParameterNotNull(cartridge, "cartridge");
    this.checkParameterNotNull(operate, "operate");

    verifyToSaveCartridge(cartridge);
    boolean isNew = cartridge.getUuid() == null;
    EntityLogger logger = new EntityLogger(this);
    logger.setEntity(cartridge);
    logger.setEntityConstClass(CCartridge.class);
    logger.setOperator(operate.getOperator());
    logger.setTime(operate.getTime());
    String logEvent = isNew ? EntityLogger.EVENT_ADDNEW : EntityLogger.EVENT_REMOVE;

    cartridge.setLastModified(operate.getTime());
    cartridge.setLastModifier(operate.getOperator().getNameCode());
    if (isNew)
      getSession().save(cartridge, cartridge.getAssignedUuid());
    else
      getSession().update(cartridge);

    logger.log(logEvent, null, "[" + cartridge.getPrefix() + "]" + cartridge.getCaption());
  }

  public void removeCartridge(ICartridge cartridge, OperateContext operate)
      throws BusinessException, HibernateException {
    this.checkParameterNotNull(cartridge, "cartridge");
    this.checkParameterNotNull(operate, "operate");

    EntityLogger logger = new EntityLogger(this);
    logger.setEntity(cartridge);
    logger.setEntityConstClass(CCartridge.class);
    logger.setOperator(operate.getOperator());
    logger.setTime(operate.getTime());
    logger.log(EntityLogger.EVENT_REMOVE, null, "[" + cartridge.getPrefix() + "]"
        + cartridge.getCaption());

    getSession().delete(cartridge);
  }

  public void saveFunctionView(ICartFunctionView cfv, OperateContext operate)
      throws BusinessException, HibernateException {
    this.checkParameterNotNull(cfv, "cfv");
    this.checkParameterNotNull(operate, "operate");
    assert cfv.getCartridge() != null;

    verifyToSaveFunctionView(cfv);
    boolean isNew = cfv.getUuid() == null;
    ICartridge cart = cfv.getCartridge();
    EntityLogger logger = new EntityLogger(this);
    logger.setEntity(cart);
    logger.setEntityConstClass(CCartridge.class);
    logger.setOperator(operate.getOperator());
    logger.setTime(operate.getTime());
    String logEvent = isNew ? EVENT_ADDNEW_CFV : EVENT_MODIFY_CFV;

    cfv.setLastModified(operate.getTime());
    cfv.setLastModifier(operate.getOperator().getNameCode());
    if (isNew)
      getSession().save(cfv, cfv.getAssignedUuid());
    else
      getSession().update(cfv);

    logger.log(logEvent, cart.getState(), "[" + cfv.getPrefix() + "]" + cfv.getGlobalCaption());
  }

  public void removeFunctionView(ICartFunctionView cfv, OperateContext operate)
      throws BusinessException, HibernateException {
    this.checkParameterNotNull(cfv, "cfv");
    this.checkParameterNotNull(operate, "operate");

    ICartridge cart = cfv.getCartridge();
    EntityLogger logger = new EntityLogger(this);
    logger.setEntity(cart);
    logger.setEntityConstClass(CCartridge.class);
    logger.setOperator(operate.getOperator());
    logger.setTime(operate.getTime());

    getSession().delete(cfv);

    logger.log(EVENT_REMOVE_CFV, null, "[" + cfv.getPrefix() + "]" + cfv.getGlobalCaption());
  }

  public ICartridge getCartridge(String uuid) throws BusinessException, HibernateException {
    this.checkParameterNotNull(uuid, "uuid");
    return (ICartridge) getSession().get(ICartridge.class, uuid);
  }

  public ICartridge getCartridgeByPrefix(String prefix) throws BusinessException,
      HibernateException {
    this.checkParameterNotNull(prefix, "prefix");
    List list = getSession().find("from " + ICartridge.class.getName() + " c where c.prefix = ?",
        prefix, Hibernate.STRING);
    if (list.size() > 0)
      return (ICartridge) list.get(0);
    else
      return null;
  }

  public List<ICartFunctionView> getFunctionViews(ICartridge cartridge) throws BusinessException,
      HibernateException {
    this.checkParameterNotNull(cartridge, "cartridge");
    List list = getSession().find(
        "from " + ICartFunctionView.class.getName() + " cfv" + " where cfv.cartridge.uuid = ?",
        cartridge.getUuid(), Hibernate.STRING);
    return (List<ICartFunctionView>) list;
  }

  public ICartFunctionView getFunctionView(String uuid) throws BusinessException,
      HibernateException {
    this.checkParameterNotNull(uuid, "uuid");
    return (ICartFunctionView) getSession().get(ICartFunctionView.class, uuid);
  }

  public ICartFunctionView getFunctionViewByPrefix(String prefix) throws BusinessException,
      HibernateException {
    this.checkParameterNotNull(prefix, "prefix");
    List list = getSession().find(
        "from " + ICartFunctionView.class.getName() + " cfv" + " where cfv.prefix = ?", prefix,
        Hibernate.STRING);
    if (list.size() > 0)
      return (ICartFunctionView) list.get(0);
    else
      return null;
  }

  public Version getDBVersion(String cartUuid) throws BusinessException {
    this.checkParameterNotNull(cartUuid, "cartUuid");

    Version ver = new Version("0.0.0.0");
    try {
      PreparedStatement ps = HibernateSession.getSession().connection().prepareStatement(
          "select version from RBCartridge where uuid = ?");
      ResultSet rs = null;
      try {
        ps.setString(1, cartUuid);
        rs = ps.executeQuery();
        if (rs.next()) {
          ver = new Version(rs.getString(1));
        }
      } finally {
        if (rs != null)
          rs.close();
      }
    } catch (Exception e) {
      Logger logger = Logger.getLogger(BCartridgeMgr.class);
      logger.warn("getDBVersion: " + e.getMessage());
    }
    return ver;
  }

  public void beginUpgradeT(String cartUuid) throws BusinessException, HibernateException {
    this.checkParameterNotNull(cartUuid, "cartUuid");

    Version version = this.getDBVersion(cartUuid);
    if (version.truncate(3).equals(new Version("0.0.0")))
      return;

    Connection conn = HibernateSession.getSession().connection();
    try {
      if (conn.getAutoCommit())
        conn.setAutoCommit(false);
      PreparedStatement ps = conn
          .prepareStatement("update RBCartridge set upgrading = ? where uuid = ?");
      ps.setInt(1, 1);
      ps.setString(2, cartUuid);
      ps.executeUpdate();
      conn.commit();
    } catch (SQLException e) {
      try {
        conn.rollback();
      } catch (SQLException e2) {
      }
      throw new BusinessException(e);
    }

    tryToRefreshCartridge(cartUuid);
  }

  public void endUpgradeT(String cartUuid, Version version) throws BusinessException,
      HibernateException {
    this.checkParameterNotNull(cartUuid, "cartUuid");
    this.checkParameterNotNull(version, "version");

    Connection conn = HibernateSession.getSession().connection();
    try {
      if (conn.getAutoCommit())
        conn.setAutoCommit(false);
      PreparedStatement ps = conn
          .prepareStatement("update RBCartridge set upgrading = ?, version = ? where uuid = ?");
      ps.setInt(1, 0);
      ps.setString(2, version.toString());
      ps.setString(3, cartUuid);
      ps.executeUpdate();
      conn.commit();
    } catch (SQLException e) {
      try {
        conn.rollback();
      } catch (SQLException e2) {
      }
      throw new BusinessException(e);
    }

    tryToRefreshCartridge(cartUuid);
  }

  private void verifyToSaveCartridge(ICartridge cartridge) throws BusinessException,
      HibernateException {
    assert cartridge != null;

    if (cartridge.getUuid() == null && cartridge.getAssignedUuid() == null)
      throw new BusinessException("必须指定被保存" + cartridge.getClass().getName() + "的uuid属性。");

    String uuid = cartridge.getUuid();
    if (uuid == null)
      uuid = cartridge.getAssignedUuid();
    ICartridge cart2 = this.getCartridgeByPrefix(cartridge.getPrefix());
    if (cart2 != null && !cart2.getUuid().equals(uuid))
      throw new BusinessException("已经存在相同" + CCartridge.CAPTION_PREFIX + "("
          + cartridge.getPrefix() + ")的" + CCartridge.CAPTION_CLASS + "。");
  }

  private void verifyToSaveFunctionView(ICartFunctionView cfv) throws BusinessException,
      HibernateException {
    assert cfv != null;

    if (cfv.getUuid() == null && cfv.getAssignedUuid() == null)
      throw new BusinessException("必须指定被保存" + cfv.getClass().getName() + "的uuid属性。");

    String uuid = cfv.getUuid();
    if (uuid == null)
      uuid = cfv.getAssignedUuid();
    ICartFunctionView cfv2 = this.getFunctionViewByPrefix(cfv.getPrefix());
    if (cfv2 != null && !cfv2.getUuid().equals(uuid))
      throw new BusinessException("已经存在相同" + CCartFunctionView.CAPTION_PREFIX + "("
          + cfv.getPrefix() + ")的" + CCartFunctionView.CAPTION_CLASS + "。");
  }

  /**
   * 尝试刷新Hibernate缓冲中指定的ICartridge对象。
   * 
   * @param cartUuid
   */
  private void tryToRefreshCartridge(String cartUuid) {
    try {
      ICartridge cart = this.getCartridge(cartUuid);
      getSession().refresh(cart);
    } catch (Exception e) {
    }
  }

}
